上一篇文章是透過 linux 內建的 socketcan 來做指令測試,這篇文章會說明該如何使用 C++ 來實現上篇的功能,以及我們需要做哪些前置。
這邊提供兩種方式來安裝,第一種是for 32 bit 的處理器 ,第二種是 for 64 bit 的處理器。
#for arm32
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabi
sudo apt-get install g++-arm-linux-gnueabihf
which arm-linux-gnueabihf-gcc
which arm-linux-gnueabihf-g++
export PATH=$PATH:$/usr/bin/arm-linux-gnueabihf-g++
export PATH=$PATH:$/usr/bin/arm-linux-gnueabihf-gcc
#for arm64
sudo apt update
sudo apt install gcc make gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
which aarch64-linux-gnu-gcc
which aarch64-linux-gnu-g++
which aarch64-linux-gnu-ld
export PATH=$PATH:$/usr/bin/aarch64-linux-gnu-gcc
export PATH=$PATH:$/usr/bin/aarch64-linux-gnu-g++
export PATH=$PATH:$/usr/bin/aarch64-linux-gnu-ld
#include <iostream>
#include <linux/can.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/can/raw.h>
#include <unistd.h>
#include <cstdlib>
#include <string.h>
#include <atomic>
#include <signal.h>
#include <thread>
#include <condition_variable>
#include <mutex>
#define ip_cmd_set_can0_params "ip link set can0 type can bitrate 1000000 dbitrate 2000000 fd on"
#define ip_cmd_can0_up "ip link set can0 up"
#define ip_cmd_can0_down "ip link set can0 down"
int can_fd;
int system_call_up()
{
int result = system(ip_cmd_set_can0_params);
if (result == -1) {
std::cerr << "Failed to set CAN0 parameters." << std::endl;
return -1;
}
sleep(1);
result = system(ip_cmd_can0_up);
if (result == -1) {
std::cerr << "Failed to bring up CAN0." << std::endl;
return -1;
}
return 1;
}
int system_call_down()
{
int result;
result = system(ip_cmd_can0_down);
if (result == -1) {
std::cerr << "Failed to bring down CAN0." << std::endl;
return -1;
}
else
return 1;
}
int can_init()
{
if(system_call_up() == -1)
{
std::cout << "BringUp CAN0 Failed" << std::endl;
return -1;
}
sleep(1);
can_fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
if(can_fd < 0)
{
perror("socket can creat error!\n");
return -1;
}
struct ifreq ifr; // if.h
strcpy(ifr.ifr_name, "can0"); // search can 0
ioctl(can_fd, SIOCGIFINDEX, &ifr);
struct sockaddr_can addr;
addr.can_family = AF_CAN; // can procotol family
addr.can_ifindex = ifr.ifr_ifindex; // can device index
//bind can and socket
int bind_res = bind(can_fd, (struct sockaddr *)&addr, sizeof(addr));
if(bind_res < 0)
{
perror("bind error!");
return -1;
}
// set filter , and only receive ID is 1 2 3 Frame Data
struct can_filter rfilter[3];
rfilter[0].can_id = 1;
rfilter[0].can_mask = CAN_SFF_MASK; // (SFF: standard frame format)
rfilter[1].can_id = 2;
rfilter[1].can_mask = CAN_SFF_MASK;
rfilter[2].can_id = 3;
rfilter[2].can_mask = CAN_SFF_MASK;
setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
return can_fd;
}
//if return is -1 , failed
//if successfully , return write data size
int write_data()
{
struct can_frame frame;
frame.data[0] = 0xFF;
frame.data[1] = 0xFF;
frame.data[2] = 0xDD;
frame.data[3] = 0xEE;
frame.data[4] = 0xBB;
frame.data[5] = 0xCC;
frame.data[6] = 0xAA;
frame.data[7] = 0xFC;
frame.can_dlc = 8;
frame.can_id = 1;
write(can_fd, &frame, sizeof(frame));
std::cout << "[CAN Send Data] ";
for(int i = 0 ; i < 8 ; i++)
{
std::cout << std::hex << (uint16_t)frame.data[i] << " ";
}
std::cout << std::endl;
}
int read_data()
{
struct can_frame status;
read(can_fd, &status, sizeof(status));
int s_data = status.can_dlc;
std::cout <<"[CAN ID ] "<<(uint16_t)status.can_id << std::endl;
std::cout <<"[CAN DLC ] "<<(uint16_t)s_data << std::endl;
std::cout <<"[CAN DATA] ";
for(int i = 0 ; i < s_data ; i++)
{
std::cout << std::hex << (uint16_t)status.data[i] << " ";
}
std::cout << std::endl;
}
int time_count = 0;
int main()
{
if(time_count == 0)
{
int res = can_init();
if(res<0)
{
std::cout << "CAN Init Error" << std::endl;
return -1;
}
else
{
std::cout << "CAN Init OK!" << std::endl;
time_count++;
}
}
while(true)
{
write_data();
sleep(0.5);
}
std::cout << "Exiting gracefully..." << std::endl;
close(can_fd);
return 0;
}
#include <iostream>
#include <linux/can.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/can/raw.h>
#include <unistd.h>
#include <cstdlib>
#include <string.h>
#include <signal.h>
#include <thread>
#include <condition_variable>
#include <mutex>
#define ip_cmd_set_can0_params "ip link set can0 type can bitrate 1000000 dbitrate 2000000 fd on"
#define ip_cmd_can0_up "ip link set can0 up"
#define ip_cmd_can0_down "ip link set can0 down"
int can_fd;
int system_call_up()
{
int result = system(ip_cmd_set_can0_params);
if (result == -1) {
std::cerr << "Failed to set CAN0 parameters." << std::endl;
return -1;
}
sleep(1);
result = system(ip_cmd_can0_up);
if (result == -1) {
std::cerr << "Failed to bring up CAN0." << std::endl;
return -1;
}
return 1;
}
int system_call_down()
{
int result;
result = system(ip_cmd_can0_down);
if (result == -1) {
std::cerr << "Failed to bring down CAN0." << std::endl;
return -1;
}
else
return 1;
}
int can_init()
{
if(system_call_up() == -1)
{
std::cout << "BringUp CAN0 Failed" << std::endl;
return -1;
}
sleep(1);
can_fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
if(can_fd < 0)
{
perror("socket can creat error!\n");
return -1;
}
struct ifreq ifr; // if.h
strcpy(ifr.ifr_name, "can0"); // search can 0
ioctl(can_fd, SIOCGIFINDEX, &ifr);
struct sockaddr_can addr;
addr.can_family = AF_CAN; // can procotol family
addr.can_ifindex = ifr.ifr_ifindex; // can device index
//bind can and socket
int bind_res = bind(can_fd, (struct sockaddr *)&addr, sizeof(addr));
if(bind_res < 0)
{
perror("bind error!");
return -1;
}
// set filter , and only receive ID is 1 2 3 Frame Data
struct can_filter rfilter[3];
rfilter[0].can_id = 1;
rfilter[0].can_mask = CAN_SFF_MASK; // (SFF: standard frame format)
rfilter[1].can_id = 2;
rfilter[1].can_mask = CAN_SFF_MASK;
rfilter[2].can_id = 3;
rfilter[2].can_mask = CAN_SFF_MASK;
setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
return can_fd;
}
//if return is -1 , failed
//if successfully , return write data size
int write_data()
{
struct can_frame frame;
frame.data[0] = 0xFF;
frame.data[1] = 0xFF;
frame.data[2] = 0xDD;
frame.data[3] = 0xEE;
frame.data[4] = 0xBB;
frame.data[5] = 0xCC;
frame.data[6] = 0xAA;
frame.data[7] = 0xFC;
frame.can_dlc = 8;
frame.can_id = 1;
write(can_fd, &frame, sizeof(frame));
std::cout << "[CAN Send Data] ";
for(int i = 0 ; i < 8 ; i++)
{
std::cout << std::hex << (uint16_t)frame.data[i] << " ";
}
std::cout << std::endl;
}
int read_data()
{
struct can_frame status;
read(can_fd, &status, sizeof(status));
int s_data = status.can_dlc;
std::cout <<"[CAN ID ] "<<(uint16_t)status.can_id << std::endl;
std::cout <<"[CAN DLC ] "<<(uint16_t)s_data << std::endl;
std::cout <<"[CAN DATA] ";
for(int i = 0 ; i < s_data ; i++)
{
std::cout << std::hex << (uint16_t)status.data[i] << " ";
}
std::cout << std::endl;
}
int time_count = 0;
int main()
{
if(time_count == 0)
{
int res = can_init();
if(res<0)
{
std::cout << "CAN Init Error" << std::endl;
return -1;
}
else
{
std::cout << "CAN Init OK!" << std::endl;
time_count++;
}
}
while(true)
{
read_data();
sleep(0.5);
}
std::cout << "Exiting gracefully..." << std::endl;
close(can_fd);
return 0;
}
#include <iostream>
#include <linux/can.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/can/raw.h>
#include <unistd.h>
#include <cstdlib>
#include <string.h>
#include <atomic>
#include <signal.h>
#include <thread>
#include <condition_variable>
#include <mutex>
#define ip_cmd_set_can0_params "ip link set can0 type can bitrate 1000000 dbitrate 2000000 fd on loopback on"
#define ip_cmd_can0_up "ip link set can0 up"
#define ip_cmd_can0_down "ip link set can0 down"
int can_fd;
int system_call_up()
{
int result = system(ip_cmd_set_can0_params);
if (result == -1) {
std::cerr << "Failed to set CAN0 parameters." << std::endl;
return -1;
}
sleep(1);
result = system(ip_cmd_can0_up);
if (result == -1) {
std::cerr << "Failed to bring up CAN0." << std::endl;
return -1;
}
return 1;
}
int system_call_down()
{
int result;
result = system(ip_cmd_can0_down);
if (result == -1) {
std::cerr << "Failed to bring down CAN0." << std::endl;
return -1;
}
else
return 1;
}
int can_init()
{
if(system_call_up() == -1)
{
std::cout << "BringUp CAN0 Failed" << std::endl;
return -1;
}
sleep(1);
can_fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
if(can_fd < 0)
{
perror("socket can creat error!\n");
return -1;
}
struct ifreq ifr; // if.h
strcpy(ifr.ifr_name, "can0"); // search can 0
ioctl(can_fd, SIOCGIFINDEX, &ifr);
struct sockaddr_can addr;
addr.can_family = AF_CAN; // can procotol family
addr.can_ifindex = ifr.ifr_ifindex; // can device index
//bind can and socket
int bind_res = bind(can_fd, (struct sockaddr *)&addr, sizeof(addr));
if(bind_res < 0)
{
perror("bind error!");
return -1;
}
// set filter , and only receive ID is 1 2 3 Frame Data
struct can_filter rfilter[3];
rfilter[0].can_id = 1;
rfilter[0].can_mask = CAN_SFF_MASK; // (SFF: standard frame format)
rfilter[1].can_id = 2;
rfilter[1].can_mask = CAN_SFF_MASK;
rfilter[2].can_id = 3;
rfilter[2].can_mask = CAN_SFF_MASK;
setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
return can_fd;
}
//if return is -1 , failed
//if successfully , return write data size
int write_data()
{
struct can_frame frame;
frame.data[0] = 0xFF;
frame.data[1] = 0xFF;
frame.data[2] = 0xDD;
frame.data[3] = 0xEE;
frame.data[4] = 0xBB;
frame.data[5] = 0xCC;
frame.data[6] = 0xAA;
frame.data[7] = 0xFC;
frame.can_dlc = 8;
frame.can_id = 1;
write(can_fd, &frame, sizeof(frame));
std::cout << "[CAN Send Data] ";
for(int i = 0 ; i < 8 ; i++)
{
std::cout << std::hex << (uint16_t)frame.data[i] << " ";
}
std::cout << std::endl;
}
int read_data()
{
struct can_frame status;
read(can_fd, &status, sizeof(status));
int s_data = status.can_dlc;
std::cout <<"[CAN ID ] "<<(uint16_t)status.can_id << std::endl;
std::cout <<"[CAN DLC ] "<<(uint16_t)s_data << std::endl;
std::cout <<"[CAN DATA] ";
for(int i = 0 ; i < s_data ; i++)
{
std::cout << std::hex << (uint16_t)status.data[i] << " ";
}
std::cout << std::endl;
}
int time_count = 0;
int main()
{
if(time_count == 0)
{
int res = can_init();
if(res<0)
{
std::cout << "CAN Init Error" << std::endl;
return -1;
}
else
{
std::cout << "CAN Init OK!" << std::endl;
time_count++;
}
}
while(true)
{
write_data();
sleep(0.5);
read_data();
}
std::cout << "Exiting gracefully..." << std::endl;
close(can_fd);
return 0;
}
當我們寫好程式後,接下來要做的就是將我們的程式透過交叉編譯器編譯成執行檔,並且是可以在 stm32mp1 上運行的版本。實際上的做法就是透過 Make File 與 前面所說的交叉編譯器來做。
PROG1 = cansend
SRCS1 = can_send.cpp
PROG2 = canreceive
SRCS2 = can_receive.cpp
PROG3 = canloopback
SRCS3 = can_loopback.cpp
CLEANFILES = $(PROG1) $(PROG2) $(PROG3)
CROSS_COMPILE ?= aarch64-linux-gnu-
CC := $(CROSS_COMPILE)gcc
CXX := $(CROSS_COMPILE)g++
LD := $(CROSS_COMPILE)ld
CFLAGS = -Wall -O -g
CXXFLAGS = -Wall -O -g
all: $(PROG1) $(PROG2) $(PROG3)
$(PROG1): $(SRCS1)
$(CXX) -o $@ $^ $(CXXFLAGS)
$(PROG2): $(SRCS2)
$(CXX) -o $@ $^ $(CXXFLAGS)
$(PROG3): $(SRCS3)
$(CXX) -o $@ $^ $(CXXFLAGS)
clean:
rm -f $(PROG1) $(PROG2) $(PROG3) $(patsubst %.c, %.o, $(SRCS1)) $(patsubst %.c, %.o, $(SRCS2)) $(patsubst %.c, %.o, $(SRCS3))
# rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))
我們有了執行檔後,接下來就可以透過 yocto 將檔案安裝在對應的目錄底下。但通常會做這步驟是最後已經開發了差不多的時候,前期其實避免麻煩與編譯時間,可以直接複製到SD卡當中去執行就好了。
SUMMARY = "bitbake-layers recipe"
DESCRIPTION = "Recipe created by bitbake-layers"
LICENSE = "CLOSED"
SRC_URI = "file://can_test/canreceive \
file://can_test/cansend \
file://can_test/canloopback \
"
S = "${WORKDIR}"
RDEPENDS:${PN} += "libgcc libstdc++ glibc"
do_install() {
install -d ${D}${sysconfdir}/test
install -m 0755 ${WORKDIR}/can_test/canreceive ${D}${sysconfdir}/test
install -m 0755 ${WORKDIR}/can_test/cansend ${D}${sysconfdir}/test
install -m 0755 ${WORKDIR}/can_test/canloopback ${D}${sysconfdir}/test
}
重新編譯後,檔案會存放在 /etc/test/ 底下 。 可以直接使用 ./canloopback 做單板測試。